import { useEffect } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as CANNON from "cannon-es";

import { CannonEsDebuggerPro } from "@vladkrutenyuk/cannon-es-debugger-pro";

function App() {
  useEffect(() => {
    // 创建世界
    const scene = new THREE.Scene();
    // 创建相机
    const camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    // 设置相机位置
    camera.position.z = 0;
    camera.position.x = 5;
    camera.position.y = 5;
    camera.lookAt(0, 20, 0); // 设置相机朝向

    const root = new THREE.Group();
    scene.add(root); // 将根节点添加到场景中

    // 创建两个数组更新物理世界和threejs世界
    const cannonBodies = [];
    const threeObjects = [];

    // 创建物理世界
    const world = new CANNON.World();
    // 允许休眠
    world.allowSleep = true;

    const color = 0xe60c0c; // or 'rgb(228, 14, 88)', '#e60c0c', 'red'
    const offset = 0.009;
    const cannonDebugger = new CannonEsDebuggerPro(root, world, color, offset);

    // 物理世界分组
    const group1 = 1; // 物理世界分组1
    const group2 = 2; // 物理世界分组2
    const group3 = 4; // 物理世界分组3
    const group4 = 8; // 物理世界分组4

    {
      // 设置重力
      world.gravity.set(0, -9.82, 0); // m/s²

      // 添加物理材质
      const boxMaterial = new CANNON.Material("boxMaterial"); // 创建材质
      boxMaterial.friction = 0; // 摩擦力
      // boxMaterial.restitution = 0.9; // 弹性

      // 添加光滑物理材质
      const boxSlipperyMaterial = new CANNON.Material("boxSlipperyMaterial");
      boxSlipperyMaterial.friction = 0; // 摩擦力

      // 添加弹性物理材质
      const boxElasticityMaterial = new CANNON.Material(
        "boxElasticityMaterial"
      );
      boxElasticityMaterial.friction = 0; // 摩擦力
      boxElasticityMaterial.restitution = 0.9; // 弹性

      {
        var boxBody1 = null;
        var boxBody2 = null;
        {
          // 创建立方体
          const boxShape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)); // 创建立方体形状
          const boxBody = new CANNON.Body({
            mass: 0, // 质量
            position: new CANNON.Vec3(0, 4, 0), // 初始位置
            material: boxMaterial, // 使用摩擦力材质
          });
          boxBody.addShape(boxShape); // 添加形状
          world.addBody(boxBody); // 添加到物理世界
          cannonBodies.push(boxBody); // 添加到物理世界
          boxBody1 = boxBody; // 记录第一个立方体的物理世界
          // 创建threejs立方体
          const boxGeometry = new THREE.BoxGeometry(1, 1, 1); // 创建立方体几何体
          const boxMaterial1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); // 创建材质
          const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial1); // 创建threejs立方体
          root.add(boxMesh); // 添加到根节点
          threeObjects.push(boxMesh); // 添加到threejs世界
        }

        {
          // 创建立方体
          const boxShape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)); // 创建立方体形状
          const boxBody = new CANNON.Body({
            mass: 1, // 质量
            position: new CANNON.Vec3(0, 2, 0), // 初始位置
            material: boxMaterial, // 使用摩擦力材质
          });
          boxBody.addShape(boxShape); // 添加形状
          world.addBody(boxBody); // 添加到物理世界
          cannonBodies.push(boxBody); // 添加到物理世界
          boxBody2 = boxBody; // 记录第一个立方体的物理世界

          // 创建threejs立方体
          const boxGeometry = new THREE.BoxGeometry(1, 1, 1); // 创建立方体几何体
          const boxMaterial1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); // 创建材质
          const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial1); // 创建threejs立方体
          root.add(boxMesh); // 添加到根节点
          threeObjects.push(boxMesh); // 添加到threejs世界
        }
      }

      {
        // 添加弹簧约束
        let spring = new CANNON.Spring(boxBody1, boxBody2,{
            restLength: 2, // 弹簧的初始长度
            stiffness: 100, // 弹簧的刚度
            damping: 0.1, // 弹簧的阻尼
        })
        world.addEventListener('preStep', function() {
            spring.applyForce()
        })
      }

      // 添加地面
      {
        // 创建平面
        const planeShape = new CANNON.Plane();
        const planeBody = new CANNON.Body({
          mass: 0, // 质量为0表示静止物体
          position: new CANNON.Vec3(0, -0.5, 0), // 初始位置
          material: boxMaterial, // 使用摩擦力材质
          collisionFilterGroup: group4, // 物理分组
        });
        // 设置平面的旋转
        planeBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); // 绕x轴旋转90度
        planeBody.addShape(planeShape);
        world.addBody(planeBody);
      }
    }

    {
      {
      }

      {
        // 创建平面
        const planeShape = new THREE.BoxGeometry(10, 0.1, 10);
        const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
        const plane = new THREE.Mesh(planeShape, planeMaterial);
        // 设置平面位置
        plane.position.y = -0.5;
        // 将平面添加到场景中
        scene.add(plane);
      }
    }

    // 创建渲染器
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    // 将渲染器添加到DOM中
    document.getElementById("app").appendChild(renderer.domElement);

    // 添加轨道控制器
    const controls = new OrbitControls(camera, renderer.domElement);

    // 创建动画函数
    const animate = function () {
      // 更新物理世界
      world.step(1 / 60); // 60fps
      // 更新threejs世界
      for (let i = 0; i < cannonBodies.length; i++) {
        const body = cannonBodies[i];
        const mesh = threeObjects[i];
        // 更新threejs物体的位置和旋转
        mesh.position.copy(body.position);
        mesh.quaternion.copy(body.quaternion);
      }
      cannonDebugger.update(); // 更新调试器

      // 更新轨道控制器
      controls.update();

      requestAnimationFrame(animate);

      // 渲染场景
      renderer.render(scene, camera);
    };
    // 调用动画函数
    animate();

    return () => {
      // 清除渲染器
      renderer.dispose();
      // 清除场景
      scene.clear();
      // 清除相机
      camera.clear();
      // 清除渲染器DOM
      const app = document.getElementById("app");
      if (app) {
        app.removeChild(renderer.domElement);
      }
    };
  }, []);
  return <div id="app"></div>;
}

export default App;
